/*
 * ArCoLIVE - Live Internet Videoconference Environment
 * Information Technology Departament - Federal University of Alagoas - Brazil
 *
 * Copyright (C) 2005 Leandro Melo de Sales (leandro@labpesquisas.tci.ufal.br)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package br.ufal.tci.nexos.arcolive.service.conference;

import java.awt.Dimension;

import javax.media.Codec;
import javax.media.Control;
import javax.media.Format;
import javax.media.Owned;
import javax.media.Player;
import javax.media.Processor;
import javax.media.control.QualityControl;
import javax.media.format.VideoFormat;


/**
 * CLASSNAME.java
 *
 * CLASS DESCRIPTION
 *
 * @see CLASSNAME
 *
 * @author <a href="mailto:felipe@labpesquisas.tci.ufal.br">Felipe Barros Pontes</a>.
 * @author <a href="mailto:leandro@labpesquisas.tci.ufal.br">Leandro Melo de Sales</a>.
 * @since 0.1
 * @version 0.1
 *
 * <p><b>Revisions:</b>
 *
 * <p><b>yyyymmdd USERNAME:</b>
 * <ul>
 * <li> VERSION
 * </ul>
 */
public class ConferenceUtil {

    /**
     * For JPEG and H263, we know that they only work for particular
     * sizes.  So we'll perform extra checking here to make sure they
     * are of the right sizes.
     */
    public static Format checkForVideoSizes(Format original, Format supported) {

		int width, height;
		Dimension size = ((VideoFormat)original).getSize();
		Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
		Format h263Fmt = new Format(VideoFormat.H263_RTP);

		if (supported.matches(jpegFmt)) {
		    // For JPEG, make sure width and height are divisible by 8.
		    width = (size.width % 8 == 0 ? size.width :
					(int)(size.width / 8) * 8);
		    height = (size.height % 8 == 0 ? size.height :
					(int)(size.height / 8) * 8);
		} else if (supported.matches(h263Fmt)) {
		    // For H.263, we only support some specific sizes.
		    if (size.width < 128) {
				width = 128;
				height = 96;
		    } else if (size.width < 176) {
				width = 176;
				height = 144;
		    } else {
				width = 352;
				height = 288;
		    }
		} else {
		    // We don't know this particular format.  We'll just
		    // leave it alone then.
		    return supported;
		}
	
		return (new VideoFormat(null, 
					new Dimension(width, height), 
					Format.NOT_SPECIFIED,
					null,
					Format.NOT_SPECIFIED)).intersects(supported);
    }


    /**
     * Setting the encoding quality to the specified value on the JPEG encoder.
     * 0.5 is a good default.
     */
    public static void setJPEGQuality(Player p, float val) {

		Control cs[] = p.getControls();
		QualityControl qc = null;
		VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);
	
		// Loop through the controls to find the Quality control for
	 	// the JPEG encoder.
		for (int i = 0; i < cs.length; i++) {
		    if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) {
				Object owner = ((Owned)cs[i]).getOwner();
				// Check to see if the owner is a Codec.
				// Then check for the output format.
				if (owner instanceof Codec) {
				    Format fmts[] = ((Codec)owner).getSupportedOutputFormats(null);
				    for (int j = 0; j < fmts.length; j++) {
						if (fmts[j].matches(jpegFmt)) {
						    qc = (QualityControl)cs[i];
				    		qc.setQuality(val);
						    System.err.println("- Setting quality to " + val + " on " + qc);
						    break;
						}
				    }
				}
				if (qc != null) break;
		    }
		}
    }
    
    /****************************************************************
     * Convenience methods to handle processor's state changes.
     ****************************************************************/
    
    private static Integer stateLock = new Integer(0);
    private static boolean failed = false;
    
    public static Integer getStateLock() {
    	return stateLock;
    }
    
    public static void setFailed() {
    	failed = true;
    }

    public static synchronized boolean waitForState(Processor p, int state) {
		p.addControllerListener(new ProcessorStateListener());
		failed = false;

		// Call the required method on the processor
		if (state == Processor.Configured) {
		    p.configure();
		} else if (state == Processor.Realized) {
		    p.realize();
		}
		
		// Wait until we get an event that confirms the
		// success of the method, or a failure event.
		// See StateListener inner class
		while (p.getState() < state && !failed) {
		    synchronized (getStateLock()) {
				try {
				    getStateLock().wait();
				} catch (InterruptedException ie) {
				    return false;
				}
		    }
		}

		return !failed;
    }    
    
}
